/****************************************************************************
 * Elisa 1.0                                                                *
 *--------------------------------------------------------------------------*
 * Author: Laurent Granvilliers, Vincent Sorin                              *
 * Copyright (c) 2004 Laboratoire d'Informatique de Nantes Atlantique       *
 *--------------------------------------------------------------------------*
 * Elisa is distributed WITHOUT ANY WARRANTY. Read the associated           *
 * COPYRIGHT file for more details.                                         *
 *--------------------------------------------------------------------------*
 * elisa_search_strategy.cpp                                                *
 ****************************************************************************/

#include "elisa_search_strategy.h"

USING_ELISA


//--------------------------------------------------------------------------
// class SplitChooser
//--------------------------------------------------------------------------

SplitChooser::SplitChooser(ChoiceStrategy *s)
	: m_varSet(), m_varSetMap(), m_strategy(ChoiceStrategyPtr(s)), m_maxPriority(0)
	  //, m_sc()
{
	m_strategy->setChooser(this);
}


SplitChooser::~SplitChooser()
{
	/*
 	   MapSetVar::iterator it;
 	   for (it = _mapSetVar.begin(); it!= _mapSetVar.end(); ++it)
 	   {
 	   delete (*it).second;
 	   }
	delete m_strategy;
 	 */
	// kludge
	m_varSet.clear();
}

void SplitChooser::insert(VarImplPtr v)
{
	m_varSet.insert(v);

	if (m_varSetMap[v->getPriority()] == NULL)
		m_varSetMap[v->getPriority()] = VariableSetPtr(new VariableSet(v->getPriority()));

	m_varSetMap[v->getPriority()]->insert(v);

	if (v->getPriority() > m_maxPriority)
		m_maxPriority = v->getPriority();
}

void SplitChooser::setChoiceStrategy(ChoiceStrategy *s)
{
	//delete m_currentStrategy;
	m_strategy = ChoiceStrategyPtr(s);
	m_strategy->setChooser(this);
}


VarImplPtr SplitChooser::get() throw (SplitChooser::NoSplitableVar)
{
	return(m_strategy->get());
}

bool SplitChooser::isSolution()
{
	VarImplSet::const_iterator imv;
	for (imv = m_varSet.begin(); imv != m_varSet.end(); ++imv) {
		if (!(SplitChooser::isSolution(**imv))) {
			return false;
		}
	}
	return true; // each variable is ok...
}

bool SplitChooser::isSolution(const VariableImpl & v) const
{
	return !(v.isSplittable());
}

VariableSet *SplitChooser::getVariables()
{
	return &m_varSet;
}

VariableSet *SplitChooser::getVariables(int priority)
{
	return m_varSetMap[priority].get();
}

int SplitChooser::getMaxPriority() const
{
	return m_maxPriority;
}


//--------------------------------------------------------------------------
// class SearchRoundRobin
//--------------------------------------------------------------------------

SearchRoundRobin::SearchRoundRobin(SplitChooser *s)
	: ChoiceStrategy(s), m_var()
{
}


SearchRoundRobin::~SearchRoundRobin()
{
}

VarImplPtr SearchRoundRobin::getLastVar()
{
	return m_var;
}

VarImplPtr SearchRoundRobin::get() throw (SplitChooser::NoSplitableVar)
{
	VariableSet *sv = m_chooser->getVariables();
	VarImplSet::const_iterator imv, itend;

	if (m_var.get()) {
		// choice between the variable after m_var and the last one in the model
		imv = m_it;

		for (++imv; imv != sv->end(); ++imv) {
			if (!(m_chooser->isSolution(**imv))) {
				m_it = imv;
				m_var = *imv;
				return m_var;
			}
		}

		// choice between the first variable in the model and the one before m_var

		itend = m_it;
		++itend;
		for (imv = sv->begin(); imv != itend; ++imv) {
			if (!(m_chooser->isSolution(**imv))) {
				m_it = imv;
				m_var = *imv;
				return m_var;
			}
		}
	} else {
		// first choice to be made (m_var==NULL)
		for (imv = sv->begin(); imv != sv->end(); ++imv) {
			if (!(m_chooser->isSolution(**imv))) {
				m_it = imv;
				m_var = *imv;
				return m_var;
			}
		}
	}
	throw SplitChooser::NoSplitableVar();
}


//--------------------------------------------------------------------------
// class SearchMaxInterval
//--------------------------------------------------------------------------

SearchMaxInterval::SearchMaxInterval(SplitChooser *s)
	: ChoiceStrategy(s)
{
}


SearchMaxInterval::~SearchMaxInterval()
{
}


VarImplPtr SearchMaxInterval::get() throw (SplitChooser::NoSplitableVar)
{
	VarImplPtr result;
	VariableSet *sv;
	for (int i = m_chooser->getMaxPriority(); i > 0; --i) {
		sv = m_chooser->getVariables(i);
		if (sv != NULL) {
			result = sv->getBest();
			
			// TODO if (result->getIndexDomain() != NULL)
			return result;
		}
	}
	throw SplitChooser::NoSplitableVar();
}
